/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-12-06
 * Time: 20:46
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Labb4.Entity
{
	/// <summary>
	/// This controler class moves its entity from one point to the next.
	/// </summary>
	public class ControlDestination : Control
	{
		#region members
		
		/// <summary>
		/// Holds the coming destinations. When one point is reached, it is removed from the
		/// list, and the next point is the target destination.
		/// </summary>
		private List<Destination>		m_Destinations;
		/// <summary>
		/// A reference to the one instance of the EntityManager
		/// </summary>
		private EntityManager			m_EntityManager;
		
		/// <summary>
		/// If the destination x coordinate is bigger than the x coordinate of the current
		/// position at the time when the entity starts moving towards the next point, this
		/// will hold true, otherwise it will hold false.
		/// </summary>
		private bool					m_DestinationXisGreater;
		/// <summary>
		/// If the destination y coordinate is bigger than the y coordinate of the current
		/// position at the time when the entity starts moving towards the next point, this
		/// will hold true, otherwise it will hold false.
		/// </summary>
		private bool					m_DestinationYisGreater;
		/// <summary>
		/// For knowing whether or not to read the first destination info
		/// </summary>
		private bool					m_FirstDestinationFound;
		
		/// <summary>
		/// For optimization
		/// </summary>
		private float					m_CurrentDestinationX;
		/// <summary>
		/// For optimization
		/// </summary>
		private float					m_CurrentDestinationY;
		/// <summary>
		/// For optimization
		/// </summary>
		private float					m_CurrentDestinationSpeed;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members.
		/// </summary>
		public ControlDestination() :
			base()
		{
			m_Destinations = new List<Destination>();
			m_EntityManager = EntityManager.Instance;
			m_DestinationXisGreater = false;
			m_DestinationYisGreater = false;
			m_FirstDestinationFound = false;
			
			m_CurrentDestinationX = 0.0f;
			m_CurrentDestinationY = 0.0f;
			m_CurrentDestinationSpeed = 0.0f;
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Clears the queue of coming destinations.
		/// </summary>
		public void RemoveAllDestinations()
		{
			m_Destinations.Clear();
			m_FirstDestinationFound = false;
		}
		
		#endregion
		
		#region overrides
		
		/// <summary>
		/// Adds a destination to the "flight path" of the controler. Before this method is called,
		/// the controler MUST have been assigned an entity, otherwise undefined behaviour may be
		/// displayed.
		/// </summary>
		/// <param name="x">The destination point's x coordinate</param>
		/// <param name="y">The destination point's y coordinate</param>
		/// <param name="speed">The speed at which to travel to the destination point</param>
		public override void AddDestination(int x, int y, float speed)
		{
			int startX = 0;
			int startY = 0;
			
			try
			{
				startX = (int)m_Entity.Xpos;
				startY = (int)m_Entity.Ypos;
			}
			catch(Exception e)
			{
				Debug.WriteLine("Oh no, exception in AddDestination..");
				Debug.Write(e.Message);
			}
			
			if(!m_FirstDestinationFound)
			{
				m_DestinationXisGreater = ((x > startX) | (x == startX));
				m_DestinationYisGreater = ((y > startY) | (y == startY));
				
				m_CurrentDestinationX = (float)x;
				m_CurrentDestinationY = (float)y;
				m_CurrentDestinationSpeed = speed;
				
				m_FirstDestinationFound = true;
			}
			
			m_Destinations.Add(new Destination((float)x, (float)y, speed));
		}
		
		/// <summary>
		/// <include file="Control.cs" path=""></include>
		/// Moves the entity towards the next destination point. If this point is passed, the
		/// entity is automatically stopped at the exact destination point. This point is then
		/// removed from the list of upcoming destination points, and if there is a nexr point,
		/// the entity will start moving towards that.
		/// </summary>
		/// <param name="deltaTime"></param>
		public override void UpdateAI(ref int deltaTime)
		{
			if(m_Entity.Active)
			{
				m_Entity.Velocity = 0.0f;
				
				if(m_Destinations.Count > 0)
				{
					if(((m_Entity.Xpos > m_CurrentDestinationX) == m_DestinationXisGreater) ||
					   ((m_Entity.Ypos > m_CurrentDestinationY) == m_DestinationYisGreater))
					{
						m_Entity.Xpos = m_CurrentDestinationX;
						m_Entity.Ypos = m_CurrentDestinationY;
						m_Destinations.RemoveAt(0);
						
						if(m_Destinations.Count > 0)
						{
							m_CurrentDestinationX = m_Destinations[0].X;
							m_CurrentDestinationY = m_Destinations[0].Y;
							m_CurrentDestinationSpeed = m_Destinations[0].Speed;
							
							m_DestinationXisGreater = ((m_CurrentDestinationX > m_Entity.Xpos) | (m_CurrentDestinationX == m_Entity.Xpos));
							m_DestinationYisGreater = ((m_CurrentDestinationY > m_Entity.Ypos) | (m_CurrentDestinationY == m_Entity.Ypos));
						}
						else
						{
							m_FirstDestinationFound = false;
						}
					}
				}
				
				if(m_Destinations.Count > 0)
				{
					m_Entity.Direction = m_EntityManager.GetDirection(m_Entity, ref m_CurrentDestinationX, ref m_CurrentDestinationY);
					m_Entity.Velocity = m_CurrentDestinationSpeed;
				}
			}
		}
		
		#endregion
		
		#region inner private classes
		
		/// <summary>
		/// A private inner class holding a destination point. Maybe this should be a struct?
		/// As a struct though, I would not be able to control the visibility of the 3 members
		/// </summary>
		private class Destination
		{
			#region members
			
			/// <summary>
			/// The destination's x coordinate.
			/// </summary>
			private float		m_X;
			/// <summary>
			/// The destination's y coordinate.
			/// </summary>
			private float		m_Y;
			/// <summary>
			/// The speed at which to travel to this destination point. Unit is (pixels/sec)
			/// </summary>
			private float		m_Speed;
			
			#endregion
			
			#region constructor
			
			/// <summary>
			/// Constructor, initializes members.
			/// </summary>
			/// <param name="x"></param>
			/// <param name="y"></param>
			/// <param name="speed"></param>
			public Destination(float x, float y, float speed)
			{
				m_X = x;
				m_Y = y;
				m_Speed = speed;
			}
			
			#endregion
			
			#region properties
			
			/// <summary>
			/// Getter for the destination's x coordinate.
			/// </summary>
			public float X
			{
				get
				{
					return m_X;
				}
			}
			
			/// <summary>
			/// Getter for the destination's y coordinate.
			/// </summary>
			public float Y
			{
				get
				{
					return m_Y;
				}
			}
			
			/// <summary>
			/// Getter for the speed at which to travel to the destination point..
			/// </summary>
			public float Speed
			{
				get
				{
					return m_Speed;
				}
			}
			
			#endregion
		}
		
		#endregion
	}
}
